package com.idealighter.game.games.zjh;

import com.idealighter.game.core.common.Game;
import com.idealighter.game.dictionary.domain.RobotConfigDomain;
import com.idealighter.game.dictionary.domain.ZhajinhuaRoomDomain;
import com.idealighter.game.dictionary.domwrapper.ZhajinhuaRoomDomWrapper;
import com.idealighter.game.gamehall.dto.SeatInfo;
import com.idealighter.game.games.zjh.message.ReqBetMsg;
import com.idealighter.game.games.zjh.message.ReqDiscardMsg;
import com.idealighter.game.games.zjh.message.ReqEnterGameHallMsg;
import com.idealighter.game.games.zjh.message.ReqEnterRoomMsg;
import com.idealighter.game.games.zjh.message.ReqFastEnterTableMsg;
import com.idealighter.game.games.zjh.message.ReqSeeCardMsg;
import com.idealighter.game.games.zjh.message.ReqVersusMsg;
import com.idealighter.game.robot.core.Player;
import com.idealighter.utils.code.RandCodeUtil;

import java.util.TreeSet;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 炸金花机器人.
 *
 */
public class ZjhPlayer extends Player {

  private static final Logger LOG = LoggerFactory.getLogger(ZjhPlayer.class);

  // 是否看牌
  public boolean sawCard;
  // 第几轮
  public int round;
  // 牌的类型(0:235,1:单张,2:对子,3:顺子,4:金华,5:顺金,6:豹子)
  public int cardsType;
  // 是否赢(看了牌以后才能确定)
  public boolean win;
  // 是否有qkq(看了牌以后才能确定)
  public boolean hasAkq;

  // 上一家下注
  public long preBet;
  // 上一家下注类型(0:暗注,非0:明注)
  public int preBetType;
  // 合计下注
  public long totalBet = 0;

  public ZhajinhuaRoomDomain roomDomain;

  /**
   * 重置数据.
   */
  public void reset() {
    this.sawCard = false;
    this.round = 1;
    this.cardsType = 0;
    this.win = false;
    this.hasAkq = false;
    this.preBet = 0;
    this.preBetType = 0;
    this.totalBet = 0;
  }

  /**
   * 构造函数.
   * 
   * @param playerId .
   * @param userName .
   * @param roomId .
   * @param initGold .
   * @param totalGameNum .
   * @param tableGameNum .
   */
  public ZjhPlayer(long playerId, String userName, int roomId, int initGold, int totalGameNum,
      int tableGameNum, RobotConfigDomain configDomain, ZhajinhuaRoomDomain roomDomain) {
    super(playerId, userName, roomId, initGold, totalGameNum, tableGameNum, configDomain);
    this.roomDomain = roomDomain;
  }

  @Override
  public void enterGameHall() {
    sendMsg(new ReqEnterGameHallMsg());
  }

  @Override
  public boolean goldCheck() {
    long gold = playerInfo.getGold();
    if (gold < roomDomain.getLower()) {
      LOG.info("[炸金花]机器人[{}][{}]金币小于房间下限退出游戏", userName, playerId);
      delayLogout();
      return false;
    }

    if (gold > roomDomain.getUpper()) {
      LOG.info("[炸金花]机器人[{}][{}]金币高于房间下限退出游戏", userName, playerId);
      delayLogout();
      return false;
    }

    if (gold < roomDomain.getAfee()) {
      LOG.info("[炸金花]机器人[{}][{}]金币小于台费退出游戏", userName, playerId);
      delayLogout();
      return false;
    }
    return true;
  }

  @Override
  public void enterRoom() {
    if (rooms.contains(roomId)) {
      if (!goldCheck()) {
        return;
      }
      ReqEnterRoomMsg msg = new ReqEnterRoomMsg();
      msg.setRoomId(roomId);
      sendMsg(msg);
    }
  }

  @Override
  public void enterTable() {
    if (!goldCheck()) {
      return;
    }
    SeatInfo emptySeat = findNoGamingEmptySeat();
    if (emptySeat != null) {
      ReqFastEnterTableMsg msg = new ReqFastEnterTableMsg();
      msg.setRoomId(roomId);

      schedule(() -> sendMsg(msg), RandCodeUtil.random(3, 5), TimeUnit.SECONDS);
    }

  }

  @Override
  public boolean enterPwdTableAble() {
    return false;
  }

  @Override
  public Game game() {
    return Game.ZJH;
  }

  /**
   * 下注.
   */
  public void bet() {
    if (sawCard) {
      if (round > 1) {
        if (win) {
          doBet(0, 40, 20, 40);
        } else {
          if (cardsType == 0 || cardsType == 1) {
            if (hasAkq) {
              doBet(10, 30, 10, 50);
            } else {
              doBet(70, 10, 10, 10);
            }
          } else if (cardsType == 2) {
            doBet(10, 30, 20, 40);
          } else {
            doBet(0, 85, 10, 5);
          }
        }

      } else {
        doBet(0, 70, 30, 0);
      }
    } else {
      if (RandCodeUtil.probable(25, 100)) { // 没有看牌,25%几率看牌
        sendMsg(new ReqSeeCardMsg());
        LOG.info("[炸金花]玩家[{}][{}]请求看牌", userName, playerId);
      } else {
        doBet(0, 80, 20, 0);
      }
    }

  }

  /**
   * 下注 .
   * 
   * @param discardPercent . 弃牌百分比
   * @param followPercent . 跟注百分比
   * @param raisePercent . 加注百分比
   * @param versusPercent . 比牌百分比
   */
  private void doBet(int discardPercent, int followPercent, int raisePercent, int versusPercent) {
    ZhajinhuaRoomDomWrapper roomDomWrapper = new ZhajinhuaRoomDomWrapper(roomDomain);
    TreeSet<Long> darkChips = roomDomWrapper.getDarkChips();
    TreeSet<Long> brightChips = roomDomWrapper.getBrightChips();

    int ranVal = RandCodeUtil.random(100);
    // 封顶
    int top = roomDomain.getTop();

    if (ranVal < discardPercent) { // 弃牌
      sendMsg(new ReqDiscardMsg());
    } else if ((ranVal -= discardPercent) < followPercent) { // 跟注
      ReqBetMsg betMsg = new ReqBetMsg();
      Long betChips = null;
      if (preBetType == 0) {
        betChips = sawCard ? brightChips.ceiling(preBet * 2) : darkChips.ceiling(preBet);
      } else {
        betChips = sawCard ? brightChips.ceiling(preBet) : darkChips.ceiling(preBet / 2);
      }

      if (totalBet >= top) {
        ReqVersusMsg versusMsg = new ReqVersusMsg();
        versusMsg.setOther(-1);
        sendMsg(versusMsg);
        LOG.info("[炸金花]玩家[{}][{}]下注超过封顶请求比牌", userName, playerId);
        return;
      }

      betMsg.setChips(betChips);
      sendMsg(betMsg);
      LOG.info("[炸金花]玩家[{}][{}]请求跟注[{}]", userName, playerId, betChips);
    } else if ((ranVal -= followPercent) < raisePercent) { // 加注
      ReqBetMsg betMsg = new ReqBetMsg();
      Long betChips = null;

      if (preBetType == 0) {
        if (sawCard) {
          betChips =
              (betChips = brightChips.higher(preBet * 2)) == null ? brightChips.ceiling(preBet * 2)
                  : betChips;
        } else {
          betChips =
              (betChips = darkChips.higher(preBet)) == null ? darkChips.ceiling(preBet) : betChips;
        }
      } else {
        if (sawCard) {
          betChips = (betChips = brightChips.higher(preBet)) == null ? brightChips.ceiling(preBet)
              : betChips;
        } else {
          betChips =
              (betChips = darkChips.higher(preBet / 2)) == null ? darkChips.ceiling(preBet / 2)
                  : betChips;
        }
      }

      if (totalBet >= top) {
        ReqVersusMsg versusMsg = new ReqVersusMsg();
        versusMsg.setOther(-1);
        sendMsg(versusMsg);
        LOG.info("[炸金花]玩家[{}][{}]下注超过封顶请求比牌", userName, playerId);
        return;
      }

      betMsg.setChips(betChips);
      sendMsg(betMsg);
      LOG.info("[炸金花]玩家[{}][{}]请求加注[{}]", userName, playerId, betChips);
    } else if ((ranVal -= raisePercent) < versusPercent) { // 比牌
      ReqVersusMsg versusMsg = new ReqVersusMsg();
      versusMsg.setOther(-1);
      sendMsg(versusMsg);
      LOG.info("[炸金花]玩家[{}][{}]请求比牌", userName, playerId);
    } else { // 弃牌
      sendMsg(new ReqDiscardMsg());
      LOG.info("[炸金花]玩家[{}][{}]请求弃牌", userName, playerId);
    }
  }

}
